package com.wy.panda.repeatrequest;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.wy.panda.common.util.DigestUtils;
import com.wy.panda.common.util.StringUtils;
import com.wy.panda.exception.PandaException;

import lombok.extern.slf4j.Slf4j;

/**
 * 重复提交限制
 *
 * @author WangYuan
 * @since 2020年12月2日 下午3:07:27
 */
@Slf4j
@Component
@Aspect
public class RequestRepeatAspect {

	@Resource(name = "valueOperations")
	private ValueOperations<String, String> valueOperations;
	
	@Before("execution(* com.wy.panda..*Controller.*(..)) && @annotation(requestRepeatControl)")
	public void checkRepeatRequest(RequestRepeatControl requestRepeatControl) {
		try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if(attributes == null) {
                log.warn("未获取到请求，不做重复提交的验证");
                return;
            }
            
            //获取当前登录人的唯一标识
            String sessionId = attributes.getSessionId();
            if(StringUtils.isBlank(sessionId)) {
                log.warn("本次请求的sessionId为空，不做重复提交的验证");
                return;
            }
            
            //获取当前请求的路径
            HttpServletRequest request = attributes.getRequest();
            String servletPath = request.getServletPath();
            if(StringUtils.isBlank(servletPath)) {
                log.warn("本次请求的servletPath为空，不做重复提交的验证");
                return;
            }
            
            //获取当前请求的参数值，只针对form表单方式提交有效，如是json方式提交，则此值只是空
            String params = request.getParameterMap()
                    .entrySet()
                    .stream()
                    .map(entry -> entry.getKey() + ":" + Arrays.toString(entry.getValue()))
                    .collect(Collectors.joining(","));
            if(StringUtils.isBlank(params)) {
                params = "";
            }
            
            String repeatRequestOriginKey = sessionId + ":" + servletPath + ":" + params;
            String repeatRequestKey = DigestUtils.md5Hex(repeatRequestOriginKey);
            
            log.info("防重复提交加密后的key：{}，原key：{}", repeatRequestKey, repeatRequestOriginKey);
            
            if(!valueOperations.setIfAbsent("repeatRequest:" + repeatRequestKey, "1", requestRepeatControl.expire(), TimeUnit.MILLISECONDS)) {
                throw new PandaException("重复提交的请求");
            }
		} catch (PandaException e) {
			throw e;
		} catch (Exception e) {
			//如果限制请求的逻辑出错了，就正常执行吧，暂时不做其他处理
			log.error("限制请求重复提交的切面进行逻辑处理时报错， 原因：", e);
		}
	}
}
